#include "applet.hpp"

#include <QtGui/QKeyEvent>
#include <QtGui/QFileDialog>
#include <QtCore/QTextStream>
#include <QtCore/QString>
#include <QtCore/QTimer>
#include <QtCore/QCoreApplication>

#include <boost/python.hpp>



#include "usb.h"
volatile bool stopLoop;
const unsigned char Range = 255;
const int CommandSize = 4;

const QString connected = "Connected";

const QString notConnected = "Not Connected";

bool
stop()
{
	return stopLoop;
}

ManualSettings m_manualSettings;
void
Applet::wait( unsigned waitTime )
{
	wait( waitTime );
}

void
Applet::baseSpeedModify(int _mod)
{
	m_manualSettings.baseSpeedMod = _mod;
}
void
Applet::arm1SpeedModify(int _mod)
{
	m_manualSettings.arm1SpeedMod = _mod;
}

void
Applet::arm2SpeedModify(int _mod)
{
	m_manualSettings.arm2SpeedMod = _mod;
}

void
Applet::jawsSpeedModify(int _mod)
{
	m_manualSettings.jawsSpeedMod = _mod;
}

void
Applet::run()
{
	stopLoop = false;
	executeCommands();
}

void
Applet::stop()
{
	stopLoop = true;
}

void 
usbCommunicaton( unsigned _command, float _move )
{
	if( _move <= 0 )
		_move = 0;
	else if( _move >= 1)
		_move = 1;

	unsigned char command[ CommandSize ];
	command[0] = _command;
	command[1] = Range * _move;
	command[2] = Range;

	sendSetting( (char*)command, CommandSize );
}


Applet::Applet()
:QWidget( 0 )
{
	m_python = new Python;

	QVBoxLayout * layout = new QVBoxLayout;
	setLayout ( layout );

	QString  title( "Available Commands:  \n wait \n base \n arm1 \n arm2 \n jaws" );

	QLabel * label = new QLabel( title );
	label->setFont (QFont ("Courier", 12));
	m_checkBox = new QCheckBox;

	edit = new TexteEdit(this);
	edit->setFont (QFont ("Courier", 12));

	m_checkBox = new QCheckBox( "enable manual control" );

	QString  controls( "Control KEys:  \n base left A \n base right S \n arm1 up T \n arm1 down G \n arm2 up  U \n arm1 down J \n jaws open O \n jaws close  P " );

	QLabel * manualControl = new QLabel( controls );
	manualControl->setFont (QFont ("Courier", 12));

	button =  new QPushButton( "run" );
	stopButton =  new QPushButton( "stop" );
	save = new QPushButton( "save" );
	load = new QPushButton( "load" );

	m_baseSlider = new QSlider( Qt::Horizontal);
	m_baseArm1Slider = new QSlider( Qt::Horizontal);
	m_baseArm2Slider = new QSlider( Qt::Horizontal);
	m_baseJawsSlider = new QSlider( Qt::Horizontal);

	m_baseSlider->setRange ( 1, 10 );
	m_baseArm1Slider->setRange ( 1, 10 );
	m_baseArm2Slider->setRange ( 1, 10 );
	m_baseJawsSlider->setRange ( 1, 10 );

	QLabel * baseSliderLabel = new QLabel("base Sensitiity");
	QLabel * m_baseArm1SliderLabel = new QLabel("arm 1 Sensitiity");
	QLabel * m_baseArm2SliderLabel = new QLabel("arm 2 Sensitiity");
	QLabel * m_baseJawsSliderLabel = new QLabel("jaws Sensitiity");

	QHBoxLayout * slider1Layout = new QHBoxLayout;
	QHBoxLayout * slider2Layout = new QHBoxLayout;
	QHBoxLayout * slider3Layout = new QHBoxLayout;
	QHBoxLayout * slider4Layout = new QHBoxLayout;

	slider1Layout->addWidget(baseSliderLabel);
	slider1Layout->addWidget(m_baseSlider);
	slider2Layout->addWidget(m_baseArm1SliderLabel);
	slider2Layout->addWidget(m_baseArm1Slider);
	slider3Layout->addWidget(m_baseArm2SliderLabel);
	slider3Layout->addWidget(m_baseArm2Slider);
	slider4Layout->addWidget(m_baseJawsSliderLabel);
	slider4Layout->addWidget(m_baseJawsSlider);

	m_manualSettings.baseSpeedMod = m_baseSlider->sliderPosition ();
	m_manualSettings.arm1SpeedMod = m_baseArm1Slider->sliderPosition ();
	m_manualSettings.arm2SpeedMod = m_baseArm2Slider->sliderPosition ();
	m_manualSettings.jawsSpeedMod = m_baseJawsSlider->sliderPosition ();

	connectButton = new QPushButton( "Connect" );
	
	m_connectionStatus = new QLabel( notConnected );

	QHBoxLayout * connectLayout = new QHBoxLayout;

	connectLayout->addWidget(connectButton);
	connectLayout->addWidget(m_connectionStatus);

	layout->addWidget(save );
	layout->addWidget(load );

	layout->addWidget(label);
	layout->addWidget(edit);
	layout->addWidget(button);
	layout->addWidget(stopButton );
	layout->addWidget(m_checkBox);
	layout->addWidget(manualControl);

	layout->addLayout(slider1Layout);
	layout->addLayout(slider2Layout);
	layout->addLayout(slider3Layout);
	layout->addLayout(slider4Layout);

	layout->addLayout(connectLayout);

	QObject::connect(m_baseSlider, SIGNAL(sliderMoved(int)),this, SLOT(baseSpeedModify(int)));
	QObject::connect(m_baseArm1Slider, SIGNAL(sliderMoved(int)),this, SLOT(arm1SpeedModify(int)));
	QObject::connect(m_baseArm2Slider, SIGNAL(sliderMoved(int)),this, SLOT(arm2SpeedModify(int)));
	QObject::connect(m_baseJawsSlider, SIGNAL(sliderMoved(int)),this, SLOT(jawsSpeedModify(int)));

	QObject::connect(m_checkBox, SIGNAL(clicked ( bool )),edit, SLOT(passEvents(bool)));
	QObject::connect(button, SIGNAL(clicked()),this, SLOT(run()));
	QObject::connect(stopButton, SIGNAL(clicked()),this, SLOT(stop()));
	QObject::connect( connectButton, SIGNAL( clicked() ),this, SLOT( connect() ) );

	QObject::connect(save, SIGNAL(clicked()),this, SLOT(saveScript()));
	QObject::connect( load, SIGNAL( clicked() ),this, SLOT( openScript() ) );
}


void
Applet::connect()
{
	if ( initialise() )
		m_connectionStatus->setText(connected);
	else
		m_connectionStatus->setText(notConnected);		

}

void
Applet::executeCommands()
{

	executeSingleCommand( edit->toPlainText() );
}

void
Applet::executeSingleCommand( QString const & _command )
{
	m_python->start( _command );
}

void
wait( unsigned waitTime )
{
	Timer timer;

	timer.wait( waitTime );
}

void 
baseSpeedModify(float _mod)
{
	usbCommunicaton( 0, _mod );
}

void 
arm1SpeedModify(float _mod)
{
	usbCommunicaton( 1, _mod );
}

void 
arm2SpeedModify(float _mod)
{
	usbCommunicaton( 2, _mod );
}

void 
jawsSpeedModify(float _mod)
{
	usbCommunicaton( 3, _mod );
}


bool Applet::event(QEvent *event)
{
	if (event->type() == QEvent::KeyPress) {
		QKeyEvent *ke = static_cast<QKeyEvent *>(event);

		switch (ke->key()) 
		{
		case Qt::Key_A:
			m_manualSettings.set(m_manualSettings.step * (float)m_manualSettings.baseSpeedMod,m_manualSettings.base);
			usbCommunicaton( 0, m_manualSettings.base );
			break;
		case Qt::Key_S:
			m_manualSettings.set(-m_manualSettings.step * (float)m_manualSettings.baseSpeedMod,m_manualSettings.base);
			usbCommunicaton( 0, m_manualSettings.base );
			break;
		case Qt::Key_T:
			m_manualSettings.set(-m_manualSettings.step * (float)m_manualSettings.arm1SpeedMod,m_manualSettings.arm1);
			usbCommunicaton( 1, m_manualSettings.arm1 );
			break;
		case Qt::Key_G:
			m_manualSettings.set(m_manualSettings.step * (float)m_manualSettings.arm1SpeedMod,m_manualSettings.arm1);
			usbCommunicaton( 1, m_manualSettings.arm1 );
			break;
		case Qt::Key_U:
			m_manualSettings.set(-m_manualSettings.step * (float)m_manualSettings.arm2SpeedMod,m_manualSettings.arm2);
			usbCommunicaton( 2, m_manualSettings.arm2 );
			break;
		case Qt::Key_J:
			m_manualSettings.set(m_manualSettings.step * (float)m_manualSettings.arm2SpeedMod,m_manualSettings.arm2);
			usbCommunicaton( 2, m_manualSettings.arm2 );
			break;
		case Qt::Key_O:
			m_manualSettings.set(-m_manualSettings.step * (float)m_manualSettings.jawsSpeedMod,m_manualSettings.jaws);
			usbCommunicaton( 3, m_manualSettings.jaws );
			break;
		case Qt::Key_P:
			m_manualSettings.set(m_manualSettings.step * (float)m_manualSettings.jawsSpeedMod,m_manualSettings.jaws);
			usbCommunicaton( 3, m_manualSettings.jaws );
			break;
			return true;
		}
	}

	return QWidget::event(event);
}

void
Applet::saveScript()
{

	QString savedFile = QFileDialog::getSaveFileName( this );

    QFile file(savedFile);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
        return;

    QTextStream out(&file);
    out << edit->toPlainText();



}
void
Applet::openScript()
{
	QString openedFile = QFileDialog::getOpenFileName( this );

    QFile file( openedFile );
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
        return;

    edit->clear();

    QString content;
    while ( !file.atEnd() )
    {
        QByteArray line = file.readLine();
        content += line;
    }
    edit->setText( content );
}

TexteEdit::TexteEdit( QWidget *  _parent )
: QTextEdit( _parent )
, m_passEvent( false )
{}

void TexteEdit::passEvents(bool _pass)
{
	m_passEvent = _pass;
}

bool TexteEdit::event(QEvent *event)
{
	if (event->type() == QEvent::KeyPress  &&  m_passEvent ) {
		event->ignore();
		false;
	}
	else
	{
		return QTextEdit::event(event);
	}
}

ManualSettings::ManualSettings()
: step( 0.01 )
{

	base = 0.0;
	arm1 = 0.0;
	arm2 = 0.0;
	jaws = 0.0;
}

void ManualSettings::set(const float _distance, float & _limb)
{
	_limb += _distance;

	if( _limb <= 0 )
		_limb = 0;
	else if( _limb >= 1)
		_limb = 1;
}


void
Timer::takeOffLock()
{
	lock = false;
}

void
Timer::wait( unsigned waitTime )
{
	lock = true;
	QTimer::singleShot(waitTime, this, SLOT( takeOffLock() ));

while( lock )
	QCoreApplication::processEvents();

}


